package com.lenovo.lcdm.type.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.lenovo.lcdm.common.enums.CommonMsgEnum;
import com.lenovo.lcdm.common.enums.DeleteFlagEnum;
import com.lenovo.lcdm.common.exception.BusinessException;
import com.lenovo.lcdm.common.exception.ServiceException;
import com.lenovo.lcdm.type.util.ContextUtil;
import com.lenovo.lcdm.type.dto.*;
import com.lenovo.lcdm.type.entity.*;
import com.lenovo.lcdm.type.service.*;
import com.lenovo.lcdm.type.mapper.TypeDefinitionMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author xujing30
* @description 针对表【type_definition】的数据库操作Service实现
* @createDate 2024-01-03 17:51:42
*/
@Service
public class TypeDefinitionServiceImpl extends ServiceImpl<TypeDefinitionMapper, TypeDefinition>
    implements TypeDefinitionService{

    private final Logger logger = LoggerFactory.getLogger(TypeDefinitionServiceImpl.class);

    private static final Long ROOT_TYPE_PARENT_ID = -1L;

    private static final Long ROOT_TYPE_ID = 0L;

    private static final String LOCAL_ATTR_TYPE_LOCAL  = "LOCAL";

    private static final String LOCAL_ATTR_TYPE_PARENT = "PARENT";

    private static String DEFAULT_GROUP_NAME = "Default";

    public static Map<Long, TypeDataType> dataTypeMap = new HashMap();
    @Autowired
    private TypeDefinitionMasterService typeDefinitionMasterService;

    @Autowired
    private TypeLocalAttributeLinkService typeLocalAttributeLinkService;

    @Autowired
    private TypeDataTypeService typeDataTypeService;

    @Autowired
    private TypeLocalAttributeSortService localAttributeSortService;

    @Autowired
    private TypeLocalAttributeService localAttributeService;

    @Autowired
    private TypeGlobalAttributeService globalAttributeService;

    @Autowired
    private TypeAttributeGroupService attributeGroupService;

    @Autowired
    private TypeAttributeGroupSortService attributeGroupSortService;


    @Override
    public TypeDefinitionDTO queryRootTypes() {

        TypeDefinitionDTO typeDefinitionDTO = new TypeDefinitionDTO();

        //查询类型定义
        LambdaQueryWrapper<TypeDefinition> typeDefinitionQw = new LambdaQueryWrapper<>();
        typeDefinitionQw.eq(TypeDefinition::getLatestIteration, true);
        typeDefinitionQw.eq(TypeDefinition::getDeleted, DeleteFlagEnum.NO.getValue());
        List<TypeDefinition> listTypeDefinition = this.list(typeDefinitionQw);
        if(CollectionUtils.isEmpty(listTypeDefinition)){
            return typeDefinitionDTO;
        }
        List typeIds = listTypeDefinition.stream().map(TypeDefinition::getMasterId).collect(Collectors.toList());
        HashMap<Long, List<TypeDefinition>> mapTypeDefinition = (HashMap<Long, List<TypeDefinition>>) listTypeDefinition.stream().collect(Collectors.groupingBy(TypeDefinition::getParentTypeId, Collectors.toList()));

        //查询类型定义Master
        LambdaQueryWrapper<TypeDefinitionMaster> typeDefinitionMasterQw = new LambdaQueryWrapper<>();
        typeDefinitionMasterQw.in(TypeDefinitionMaster::getId, typeIds);
        typeDefinitionMasterQw.eq(TypeDefinitionMaster::getDeleted, DeleteFlagEnum.NO.getValue());
        List<TypeDefinitionMaster> typeDefinitionMasters = typeDefinitionMasterService.list(typeDefinitionMasterQw);
        Map<Long, TypeDefinitionMaster> masterIdMap = typeDefinitionMasters.stream().collect(Collectors.toMap(TypeDefinitionMaster::getId, Function.identity()));

        //组装返回结果
        if (mapTypeDefinition.containsKey(ROOT_TYPE_PARENT_ID)) {
            assembleTypeDefinitionDTO(typeDefinitionDTO, mapTypeDefinition.get(ROOT_TYPE_PARENT_ID).get(0), masterIdMap);
            getNodeTypeDefinitionDTO(typeDefinitionDTO, mapTypeDefinition, masterIdMap);
        }
        return typeDefinitionDTO;
    }

    @Override
    public TypeDefinitionDTO queryDetail(Long typeId) {
        TypeDefinition definition = this.getById(typeId);
        if(definition != null){
            return this.findTypeDefinitionAttribute(definition);
        } else {
            throw new ServiceException("TypeDefinition Object is not exist" ,CommonMsgEnum.FAIL.getCode());
        }
    }

    @Override
    public TypeDefinitionDTO queryDetail(String typeInternalName) {
        List<TypeDefinitionMaster> masters = findByInternalName(typeInternalName);
        if(CollectionUtils.isEmpty(masters)){
            return null;
        }
        LambdaQueryWrapper<TypeDefinition> typeDefinitionQw = new LambdaQueryWrapper<>();
        typeDefinitionQw.eq(TypeDefinition::getLatestIteration, true);
        typeDefinitionQw.eq(TypeDefinition::getDeleted, DeleteFlagEnum.NO.getValue());
        typeDefinitionQw.eq(TypeDefinition::getMasterId, masters.get(0).getId());
        List<TypeDefinition> listTypeDefinition = this.list(typeDefinitionQw);
        if(CollectionUtils.isEmpty(listTypeDefinition)){
            return null;
        }
        TypeDefinition definition = this.getById(listTypeDefinition.get(0).getId());
        if(definition != null){
            return this.findTypeDefinitionAttribute(definition);
        } else {
            throw new ServiceException("TypeDefinition Object is not exist" ,CommonMsgEnum.FAIL.getCode());
        }
    }

    @Override
    public List<LocalAttributeDTO> queryAllLocalAttribute(Long typeId) {
        List<LocalAttributeDTO> attributeDTOList = Lists.newArrayList();

        //初始化数据类型
        initDataType();

        //类型是否存在
        TypeDefinition definition = this.getById(typeId);
        if(definition == null){
            throw new ServiceException("TypeDefinition Object is not exist" ,CommonMsgEnum.FAIL.getCode());
        }

        //查找所有当前及父类型
        List<TypeDefinition> allTypeDefinition = findParentTypeDefinition(typeId);
        List<Long> allTypeIds = allTypeDefinition.stream().map(TypeDefinition::getId).collect(Collectors.toList());

        //获取所有type link attribute
        List<TypeLocalAttributeLink> listLink = typeLocalAttributeLinkService.queryByTypeIdBatch(allTypeIds);
        if(CollectionUtils.isEmpty(listLink)){
            return attributeDTOList;
        }

        // 获取local attribute id 和 type id的映射
        Map<Long, Long> LocalAttributeTypeMap = listLink.stream().collect(Collectors.toMap(TypeLocalAttributeLink::getLocalAttributeId, TypeLocalAttributeLink::getTypeId));

        // 查询所有local attribute
        Set<Long> attributeIdSet = listLink.stream().map(TypeLocalAttributeLink::getLocalAttributeId).collect(Collectors.toSet());
        List<TypeLocalAttribute> localAttributeList = localAttributeService.listByIds(attributeIdSet);


        // 查询所有global attribute
        List<Long> globalIds = localAttributeList.stream().map(TypeLocalAttribute::getGlobalAttributeId).distinct().collect(Collectors.toList());
        Map<Long, TypeGlobalAttribute> globalMap = getGlobalAttributes(globalIds);

        // 组装LocalAttributeDTO
        attributeDTOList = localAttributeList.stream().map(attribute -> {
            LocalAttributeDTO localAttributeDTO = new LocalAttributeDTO();
            BeanUtils.copyProperties(attribute, localAttributeDTO);
            if (null != globalMap.get(attribute.getGlobalAttributeId())) {
                localAttributeDTO.setName(globalMap.get(attribute.getGlobalAttributeId()).getName());
                localAttributeDTO.setDisplayName(globalMap.get(attribute.getGlobalAttributeId()).getDisplayName());
                String dataTypeName = dataTypeMap.get(globalMap.get(attribute.getGlobalAttributeId()).getDataTypeId()).getName();
                localAttributeDTO.setDataTypeName(dataTypeName);
            } else {
                logger.error("缺少global的local：" + attribute.getId());
            }
            if(LocalAttributeTypeMap.get(attribute.getId()).intValue() == typeId.intValue()) {
                localAttributeDTO.setLocalAttrType(LOCAL_ATTR_TYPE_LOCAL);
            }else{
                localAttributeDTO.setLocalAttrType(LOCAL_ATTR_TYPE_PARENT);
            }
            localAttributeDTO.setTypeId(LocalAttributeTypeMap.get(attribute.getId()));
            return localAttributeDTO;
        }).collect(Collectors.toList());


        return attributeDTOList;
    }

    /**
     * 初始化数据类型Map
     */
    private void initDataType(){
        if (CollectionUtils.isEmpty(dataTypeMap.entrySet())) {
            LambdaQueryWrapper<TypeDataType> typeDataTypeQw = new LambdaQueryWrapper<>();
            typeDataTypeQw.eq(TypeDataType::getDeleted, DeleteFlagEnum.NO.getValue());
            List<TypeDataType> dataTypeList = typeDataTypeService.list(typeDataTypeQw);
            dataTypeMap = dataTypeList.stream().collect(Collectors.toMap(TypeDataType::getId, Function.identity()));
        }
    }

    @Override
    public TypeDefinitionDTO findTypeDefinitionAttribute(TypeDefinition definition) {
        
        //初始化数据类型
        initDataType();

        // 查找所有当前及父类型
        List<TypeDefinition> parentTypeDefinition = findParentTypeDefinition(definition.getParentTypeId());
        List<Long> parentId = parentTypeDefinition.stream().map(TypeDefinition::getId).collect(Collectors.toList());
        List<TypeDefinition> allTypeDefinition = new ArrayList<>();
        allTypeDefinition.addAll(parentTypeDefinition);
        allTypeDefinition.add(definition);

        //查询当前type的Master
        List<Long> typeMasterIds = allTypeDefinition.stream().map(TypeDefinition::getMasterId).collect(Collectors.toList());
        Map<Long, TypeDefinitionMaster> typeMasterMap = typeDefinitionMasterService.queryById(typeMasterIds);

        //先拼装查询type的属性
        TypeDefinitionDTO newTypeDefinitionDTO = new TypeDefinitionDTO();
        BeanUtils.copyProperties(definition, newTypeDefinitionDTO);
        newTypeDefinitionDTO.setInternalName(typeMasterMap.get(definition.getMasterId()).getName());
        newTypeDefinitionDTO.setReferenceClass(typeMasterMap.get(definition.getMasterId()).getReferenceClass());
        newTypeDefinitionDTO.setReferenceTable(typeMasterMap.get(definition.getMasterId()).getReferenceTable());

        //所有typeId
        List<Long> listTypeId = allTypeDefinition.stream().map(TypeDefinition::getId).collect(Collectors.toList());

        //查询所有每个type的local attribute
        Map<Long, List<LocalAttributeDTO>> localAttributeDTOByMemory = getLocalAttributeDTOByMemory(listTypeId);

        //查询所有类型下已定义的sort
        Map<Long, Map<Long, Long>> sortTypeList = localAttributeSortService.findByTypeId(listTypeId);

        //查询所有组并排序
        Map<Long, List<AttributeGroupDTO>> typeGroupMap = assumeTypeGroup(Arrays.asList(definition.getId()));
        List<Long> groupIds = typeGroupMap.get(definition.getId()).stream().map(AttributeGroupDTO::getId).collect(Collectors.toList());

        // 查找组下对应属性,主要使用组id和属性id
        List<TypeAttributeGroupAttribute> TypeAttributeGroupAttributesList = attributeGroupService.queryGroupAttribute(groupIds);
        Map<Long, Set<Long>> mapGroupAttribute =
                TypeAttributeGroupAttributesList.stream().collect(Collectors.groupingBy(TypeAttributeGroupAttribute::getGroupId, Collectors.mapping(TypeAttributeGroupAttribute::getLocalAttributeId, Collectors.toSet())));

        //组装
        assumeTypeDefinitionDTO(newTypeDefinitionDTO, definition, typeMasterMap, localAttributeDTOByMemory,
                parentId, sortTypeList.getOrDefault(definition.getId(), new HashMap<>()), typeGroupMap, mapGroupAttribute);

        return newTypeDefinitionDTO;
    }

    /**
     * 组装类型DTO
     * @param newTypeDefinitionDTO
     * @param definition
     * @param typeMasterMap
     * @param localAttributeDTOByMemory
     * @param parentId
     * @param sortTypeList
     */
    private void assumeTypeDefinitionDTO(TypeDefinitionDTO newTypeDefinitionDTO, TypeDefinition definition, Map<Long, TypeDefinitionMaster> typeMasterMap,
                                                  Map<Long, List<LocalAttributeDTO>> localAttributeDTOByMemory, List<Long> parentId, Map<Long, Long> sortTypeList, Map<Long, List<AttributeGroupDTO>> typeGroupMap, Map<Long, Set<Long>> mapGroupAttribute) {
        // 区分父类型继承属性和当前类型本地属性
        List<LocalAttributeDTO> listLocalAttributeDTO = new ArrayList<>();
        localAttributeDTOByMemory.keySet().forEach(typeId -> {
            if (!CollectionUtils.isEmpty(parentId) && parentId.contains(typeId)) {
                listLocalAttributeDTO.addAll(localAttributeDTOByMemory.get(typeId).stream().map(localAttributeDTO -> {
                    localAttributeDTO.setLocalAttrType(LOCAL_ATTR_TYPE_PARENT);
                    return localAttributeDTO;
                }).collect(Collectors.toList()));
            } else if (typeId.equals(newTypeDefinitionDTO.getId())) {
                listLocalAttributeDTO.addAll(localAttributeDTOByMemory.get(typeId));
            }
        });

        List<AttributeGroupDTO> groupDTOList = typeGroupMap.getOrDefault(definition.getId(), new ArrayList<>());
        newTypeDefinitionDTO.setAttributeGroups(groupDTOList);
        if (CollectionUtils.isEmpty(listLocalAttributeDTO)) {
            return;
        }
        //listLocalAttributeDTO中设值groupId, groupDTOList中设值local attribute
        listLocalAttributeDTO.forEach(localAttributeDTO -> {
            groupDTOList.forEach(group -> {
                if (mapGroupAttribute.getOrDefault(group.getId(), new HashSet<>()).contains(localAttributeDTO.getId())) {
                    localAttributeDTO.setGroupId(group.getId());
                    if (group.getLocalAttributes() == null) {
                        List<LocalAttributeDTO> list = new ArrayList<>();
                        list.add(localAttributeDTO);
                        group.setLocalAttributes(list);
                    } else {
                        group.getLocalAttributes().add(localAttributeDTO);
                    }
                }
            });
        });
        // 组内排序
        groupDTOList.forEach(group -> {
            group.setLocalAttributes(sortAttribute(group.getLocalAttributes(), sortTypeList));
        });

        // 设置未分组属性
        List<LocalAttributeDTO> defaultGroupAttributes = listLocalAttributeDTO.stream().filter(localAttributeDTO -> localAttributeDTO.getGroupId() == null).collect(Collectors.toList());

        groupDTOList.forEach(groupDTO -> {
            if (groupDTO.getName().equalsIgnoreCase("Default")) {
                if (groupDTO.getLocalAttributes() == null) {
                    groupDTO.setLocalAttributes(new ArrayList<>());
                }
                if(!CollectionUtils.isEmpty(defaultGroupAttributes)){
                    defaultGroupAttributes.forEach(localAttributeDTO -> localAttributeDTO.setGroupId(groupDTO.getGroupId()));
                }
                groupDTO.getLocalAttributes().addAll(defaultGroupAttributes);
                groupDTO.setLocalAttributes(sortAttribute(groupDTO.getLocalAttributes(), sortTypeList));
            }
        });
    }

    /**
     * 根据类型获取LocalAttributeDTO数据
     * @param typeIdList
     * @return 
     */
    public Map<Long, List<LocalAttributeDTO>> getLocalAttributeDTOByMemory(List<Long> typeIdList) {

        // 获取所有type link attribute
        List<TypeLocalAttributeLink> listLink = typeLocalAttributeLinkService.queryByTypeIdBatch(typeIdList);

        // 查询所有local attribute
        Set<Long> attributeIdSet = listLink.stream().map(TypeLocalAttributeLink::getLocalAttributeId).collect(Collectors.toSet());
        List<TypeLocalAttribute> localAttributeList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(attributeIdSet)) {
            localAttributeList = localAttributeService.listByIds(attributeIdSet);
        }

        // 查询所有global attribute
        List<Long> globalIds = localAttributeList.stream().map(TypeLocalAttribute::getGlobalAttributeId).distinct().collect(Collectors.toList());
        Map<Long, TypeGlobalAttribute> globalMap = getGlobalAttributes(globalIds);

        // 组装LocalAttributeDTO
        List<LocalAttributeDTO> attributeDTOList = localAttributeList.stream().map(attribute -> {
            LocalAttributeDTO localAttributeDTO = new LocalAttributeDTO();
            BeanUtils.copyProperties(attribute, localAttributeDTO);
            if (null != globalMap.get(attribute.getGlobalAttributeId())) {
                localAttributeDTO.setName(globalMap.get(attribute.getGlobalAttributeId()).getName());
                localAttributeDTO.setDisplayName(globalMap.get(attribute.getGlobalAttributeId()).getDisplayName());
                String dataTypeName = dataTypeMap.get(globalMap.get(attribute.getGlobalAttributeId()).getDataTypeId()).getName();
                localAttributeDTO.setDataTypeName(dataTypeName);
            } else {
                logger.error("缺少global的local：" + attribute.getId());
            }
            localAttributeDTO.setLocalAttrType(LOCAL_ATTR_TYPE_LOCAL);
            return localAttributeDTO;
        }).collect(Collectors.toList());

        // 组装属性 key-localAttributeId
        Map<Long, List<TypeLocalAttributeLink>> typeLocalAttributeLinkMap = listLink.stream().collect(Collectors.groupingBy(TypeLocalAttributeLink::getLocalAttributeId, Collectors.toList()));

        // 组装属性 key 为localAttributeId
        Map<Long, LocalAttributeDTO> idLocalAttributeDTOMap = attributeDTOList.stream().collect(Collectors.toMap(LocalAttributeDTO::getId, Function.identity()));

        // 填充local Attribute真实所属type，并组装
        Map<Long, List<LocalAttributeDTO>> typeLocalAttributeDTOMap = new ConcurrentHashMap<>();
        idLocalAttributeDTOMap.keySet().forEach(localAttributeId -> {
            // 添加typeID
            LocalAttributeDTO localAttributeDTO = idLocalAttributeDTOMap.get(localAttributeId);
            localAttributeDTO.setTypeId(typeLocalAttributeLinkMap.get(localAttributeId).get(0).getTypeId());
            if (typeLocalAttributeDTOMap.containsKey(typeLocalAttributeLinkMap.get(localAttributeId).get(0).getTypeId())) {
                typeLocalAttributeDTOMap.get(typeLocalAttributeLinkMap.get(localAttributeId).get(0).getTypeId()).add(localAttributeDTO);
            } else {
                List<LocalAttributeDTO> list = new ArrayList<>();
                list.add(localAttributeDTO);
                typeLocalAttributeDTOMap.put(typeLocalAttributeLinkMap.get(localAttributeId).get(0).getTypeId(), list);
            }
        });

        return typeIdList.stream().collect(Collectors.toMap((typeDefinition) -> typeDefinition, (typeDefinition) -> typeLocalAttributeDTOMap.getOrDefault(typeDefinition, new ArrayList<LocalAttributeDTO>())));
    }

    private Map<Long, List<AttributeGroupDTO>> assumeTypeGroup(List<Long> typeIds) {
        
        // 查找组排序
        LambdaQueryWrapper<TypeAttributeGroupSort> attributeGroupSortQw = new LambdaQueryWrapper<>();
        attributeGroupSortQw.in(TypeAttributeGroupSort::getTypeId, typeIds).eq(TypeAttributeGroupSort::getDeleted, DeleteFlagEnum.NO.getValue());
        List<TypeAttributeGroupSort> groupSortList = attributeGroupSortService.list(attributeGroupSortQw);

        Map<Long, Map<Long, Long>> groupSortMap = groupSortList.stream().collect(
                Collectors.groupingBy(TypeAttributeGroupSort::getTypeId, Collectors.toMap(TypeAttributeGroupSort::getGroupId, TypeAttributeGroupSort::getSortId)));
        
        // 查找组名称
        LambdaQueryWrapper<TypeAttributeGroup> attributeGroupQw = new LambdaQueryWrapper<>();
        attributeGroupQw.in(TypeAttributeGroup::getTypeId, typeIds).eq(TypeAttributeGroup::getDeleted, DeleteFlagEnum.NO.getValue());
        List<TypeAttributeGroup> groupNameList = attributeGroupService.list(attributeGroupQw);
        Map<Long, Map<Long, TypeAttributeGroup>> groupNameMap = groupNameList.stream().collect(
                Collectors.groupingBy(TypeAttributeGroup::getTypeId, Collectors.toMap(TypeAttributeGroup::getId, Function.identity())));

        Map<Long, List<AttributeGroupDTO>> mapResponse = new HashMap<>();
        for (Map.Entry<Long, Map<Long, TypeAttributeGroup>> typeGroup : groupNameMap.entrySet()) {
            List<AttributeGroupDTO> attributeGroupDTOList = new ArrayList<>();
            for (Map.Entry<Long, TypeAttributeGroup> groupName : typeGroup.getValue().entrySet()) {
                AttributeGroupDTO attributeGroupDTO = new AttributeGroupDTO();
                attributeGroupDTO.setTypeId(typeGroup.getKey());
                attributeGroupDTO.setName(groupName.getValue().getName());
                attributeGroupDTO.setDisplayName(groupName.getValue().getDisplayName());
                attributeGroupDTO.setId(groupName.getKey());
                attributeGroupDTO.setVisibility(groupName.getValue().getVisibility());
                attributeGroupDTO.setGroupId(groupName.getValue().getId());
                attributeGroupDTO.setDescription(groupName.getValue().getDescription());
                attributeGroupDTO.setSortId(groupSortMap.getOrDefault(typeGroup.getKey(), new HashMap<>()).get(groupName.getKey()));
                attributeGroupDTOList.add(attributeGroupDTO);
            }
            mapResponse.put(typeGroup.getKey(), sortGroup(attributeGroupDTOList));
        }
        return mapResponse;
    }

    private List<AttributeGroupDTO> sortGroup(List<AttributeGroupDTO> attributeGroupDTOList) {

        if (CollectionUtils.isEmpty(attributeGroupDTOList)) {
            return attributeGroupDTOList;
        }
        // 排序如果没有sortid就按照id来排序，id最大在最前
        List<AttributeGroupDTO> sortedList = attributeGroupDTOList.stream().filter(i->i.getSortId() != null).sorted(Comparator.comparing(AttributeGroupDTO::getSortId)).collect(Collectors.toList());
        List<AttributeGroupDTO> idOrderList = attributeGroupDTOList.stream().filter(i->i.getSortId() == null).sorted(Comparator.comparing(AttributeGroupDTO::getId)).collect(Collectors.toList());

        List<AttributeGroupDTO> afterSort = Lists.newArrayList();
        afterSort.addAll(sortedList);
        afterSort.addAll(idOrderList);
        for (int i = 1; i <= afterSort.size(); i++) {
            afterSort.get(i - 1).setSortId(Long.valueOf(i));
        }
        return afterSort;
    }

    public List<LocalAttributeDTO> sortAttribute(List<LocalAttributeDTO> localAttributeDTOList, Map<Long, Long> mapLocal) {

        if (CollectionUtils.isEmpty(localAttributeDTOList)) {
            return localAttributeDTOList;
        }
        // 组装sortid
        for (int i = 0; i < localAttributeDTOList.size(); i++) {
            if (mapLocal != null && mapLocal.get(localAttributeDTOList.get(i).getId()) != null) {
                localAttributeDTOList.get(i).setSortId(mapLocal.get(
                        localAttributeDTOList.get(i).getId()).intValue());
            } else {
                localAttributeDTOList.get(i).setSortId(0);
            }
        }
        // 排序如果没有sortid就按照id来排序，id最大在最前
        List<LocalAttributeDTO> sortedList = localAttributeDTOList.stream().filter(i->i.getSortId() != 0).sorted(Comparator.comparing(LocalAttributeDTO::getSortId)).collect(Collectors.toList());
        List<LocalAttributeDTO> idOrderList = localAttributeDTOList.stream().filter(i->i.getSortId() == 0).sorted(Comparator.comparing(LocalAttributeDTO::getId, Comparator.reverseOrder())).collect(Collectors.toList());

        List<LocalAttributeDTO> afterSort = Lists.newArrayList();
        afterSort.addAll(sortedList);
        afterSort.addAll(idOrderList);

        for (int i = 1; i <= afterSort.size(); i++) {
            afterSort.get(i - 1).setSortId(i);
        }
        return afterSort;
    }

    
    public Map<Long, TypeGlobalAttribute> getGlobalAttributes(List<Long> globalIds) {
        List<TypeGlobalAttribute> globalList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(globalIds)) {
            globalList = globalAttributeService.listByIds(globalIds);
        }
        return globalList.stream().collect(Collectors.toMap(TypeGlobalAttribute::getId, Function.identity()));
    }

    /**
     * 查找所有父类型
     * @param parentTypeId
     * @return
     */
    public List<TypeDefinition> findParentTypeDefinition(Long parentTypeId) {
        List<TypeDefinition> list = new ArrayList<>();
        getParentTypeDefinition(list, parentTypeId);
        return list;
    }

    /**
     * 循环查找父类型
     * @param list
     * @param id
     */
    public void getParentTypeDefinition(List<TypeDefinition> list, Long id) {
        if (!id.equals(-1L)) {
            TypeDefinition byId = this.getById(id);
            if (Objects.nonNull(byId)) {
                list.add(byId);
                getParentTypeDefinition(list, byId.getParentTypeId());
            }
        }
    }

    @Override
    public List<TypeDefinitionMaster> findByInternalName(String internalName) {
        LambdaQueryWrapper<TypeDefinitionMaster> typeDefinitionMasterQw = new LambdaQueryWrapper<>();
        typeDefinitionMasterQw.eq(TypeDefinitionMaster::getName, internalName);
        typeDefinitionMasterQw.eq(TypeDefinitionMaster::getDeleted, DeleteFlagEnum.NO.getValue());
        return typeDefinitionMasterService.list(typeDefinitionMasterQw);
    }

    @Override
    public void saveTypeDefinition(TypeDefinitionDTO typeDefinitionDTO) {

        String errorMsg = checkTypeDefinition(typeDefinitionDTO, true);
        if(StringUtils.isNotEmpty(errorMsg)){
            throw new BusinessException(errorMsg, CommonMsgEnum.FAIL.getCode());
        }

        LocalDateTime now = LocalDateTime.now();
        TypeDefinitionMaster definitionMaster = new TypeDefinitionMaster();
        definitionMaster.setName(typeDefinitionDTO.getInternalName());
        definitionMaster.setObjectClass(definitionMaster.getClass().getName());
        definitionMaster.setReferenceClass(typeDefinitionDTO.getReferenceClass());
        definitionMaster.setReferenceTable(typeDefinitionDTO.getReferenceTable());
        definitionMaster.setCreator(ContextUtil.getCurrentUser());
        definitionMaster.setModifier(ContextUtil.getCurrentUser());
        definitionMaster.setCreateTime(now);
        definitionMaster.setModifyTime(now);
        typeDefinitionMasterService.save(definitionMaster);

        TypeDefinition newType = new TypeDefinition();
        BeanUtils.copyProperties(typeDefinitionDTO, newType);
        newType.setLatestIteration(true);
        newType.setCreator(ContextUtil.getCurrentUser());
        newType.setCreateTime(now);
        newType.setModifier(ContextUtil.getCurrentUser());
        newType.setModifyTime(now);
        newType.setObjectClass(newType.getClass().getName());
        newType.setMasterId(definitionMaster.getId());
        this.save(newType);

        // 创建默认组
        TypeAttributeGroup attributeGroup = new TypeAttributeGroup();
        attributeGroup.setName(DEFAULT_GROUP_NAME);
        attributeGroup.setTypeId(newType.getId());
        attributeGroup.setCreateTime(newType.getCreateTime());
        attributeGroup.setCreator(newType.getCreator());
        attributeGroup.setModifyTime(newType.getCreateTime());
        attributeGroup.setModifier(newType.getCreator());
        attributeGroup.setDeleted(DeleteFlagEnum.NO.getValue());
        attributeGroup.setObjectClass(attributeGroup.getClass().getName());
        attributeGroupService.saveOrUpdate(attributeGroup);
    }

    @Override
    public void updateTypeDefinition(TypeDefinitionDTO typeDefinitionDTO) {
        String errorMsg = checkTypeDefinition(typeDefinitionDTO, false);
        if(StringUtils.isNotEmpty(errorMsg)){
            throw new BusinessException(errorMsg, CommonMsgEnum.FAIL.getCode());
        }
        //更新类型定义
        TypeDefinition typeDefinition = this.getById(typeDefinitionDTO.getId());
        if(typeDefinition == null){
            throw new ServiceException("TypeDefinition Object is not exist" ,CommonMsgEnum.FAIL.getCode());
        }
        BeanUtils.copyProperties(typeDefinitionDTO, typeDefinition);
        typeDefinition.setModifier(ContextUtil.getCurrentUser());
        typeDefinition.setModifyTime(LocalDateTime.now());
        this.updateById(typeDefinition);
        //Visibility是否同步到子类型定义
        if(typeDefinitionDTO.getChildEnable()){
            this.updateChildVisibility(typeDefinition.getId(), typeDefinitionDTO.getVisibility());
        }

        //if parent is root and reference class is not empty
        if(typeDefinition.getParentTypeId() == ROOT_TYPE_ID && (!StringUtils.isEmpty(typeDefinitionDTO.getReferenceClass()) || !StringUtils.isEmpty(typeDefinitionDTO.getReferenceTable()))){
            TypeDefinitionMaster typeDefinitionMaster = typeDefinitionMasterService.getById(typeDefinition.getMasterId());
            //如果有变化则更新
            typeDefinitionMaster.setReferenceClass(typeDefinitionDTO.getReferenceClass());
            typeDefinitionMaster.setReferenceTable(typeDefinitionDTO.getReferenceTable());
            typeDefinitionMaster.setModifier(ContextUtil.getCurrentUser());
            typeDefinitionMaster.setModifyTime(LocalDateTime.now());
            typeDefinitionMasterService.saveOrUpdate(typeDefinitionMaster);
            updateChildrenReferenceClass(typeDefinition.getId(), typeDefinitionDTO);
        }


    }

    /**
     * 更新子类型的Visibility
     * @param parentId
     * @param visibility
     */
    private void updateChildVisibility(Long parentId, String visibility) {
        LambdaQueryWrapper<TypeDefinition> typeDefinitionQw = new LambdaQueryWrapper<>();
        typeDefinitionQw.eq(TypeDefinition::getParentTypeId, parentId).eq(TypeDefinition::getDeleted, DeleteFlagEnum.NO.getValue());
        List<TypeDefinition> childTypeList = this.list(typeDefinitionQw);
        if (CollectionUtils.isEmpty(childTypeList)) {
            return;
        }

        List<Long> childTypeIds = childTypeList.stream().map(TypeDefinition::getId).collect(Collectors.toList());
        List<TypeDefinition> newChildTypeList = childTypeList.stream().map(item->{item.setVisibility(visibility); return item;}).collect(Collectors.toList());
        this.saveBatch(childTypeList);

        childTypeIds.forEach(type -> {
            updateChildVisibility(type, visibility);
        });
    }

    /**
     * 查询子类型
     * @param parentId
     * @return
     */
    @Override
    public List<TypeDefinition> queryByParentId(Long parentId) {
        LambdaQueryWrapper<TypeDefinition> typeDefinitionQw = new LambdaQueryWrapper<>();
        typeDefinitionQw.eq(TypeDefinition::getParentTypeId, parentId).eq(TypeDefinition::getDeleted, DeleteFlagEnum.NO.getValue());
        return this.list(typeDefinitionQw);
    }

    /**
     * 删除类型定义
     * @param typeId
     * @param checkSub
     * @param checkAttribute
     */
    @Override
    public void deleteTypeDefinition(Long typeId, boolean checkSub, boolean checkAttribute, boolean checkActualValue) {
        TypeDefinition typeDefinition = this.getById(typeId);
        if (null != typeDefinition) {
            if(typeDefinition.getDeleted().intValue() == DeleteFlagEnum.YES.getValue()){
                return;
            }
            List<TypeDefinition> subTypes = queryByParentId(typeId);
            List<TypeLocalAttributeLink> typeLocalAttributeLinks = typeLocalAttributeLinkService.queryByTypeId(typeId);
            //检查子类型和本地属性
            if(checkSub && !CollectionUtils.isEmpty(subTypes)){
                throw new BusinessException("The current type contains subtypes and cannot be deleted.", CommonMsgEnum.FAIL.getCode());
            }
            if(checkAttribute && !CollectionUtils.isEmpty(typeLocalAttributeLinks)){
                throw new BusinessException("Current type association attribute cannot be deleted !", CommonMsgEnum.FAIL.getCode());
            }
            //TO DO 检查是否有实际属性值
            if(checkActualValue){

            }


            //删除local attribute link
            if(!CollectionUtils.isEmpty(typeLocalAttributeLinks)){
                typeLocalAttributeLinkService.removeBatchByIds(typeLocalAttributeLinks);
            }
            //循环删除subType
            if(!CollectionUtils.isEmpty(subTypes)){
                subTypes.forEach(sub ->{
                    deleteTypeDefinition(sub.getId(), checkSub, checkAttribute, checkActualValue);
                });
            }
            //删除Master
            typeDefinitionMasterService.removeById(typeDefinition.getMasterId());
            this.removeById(typeId);
        } else {
           throw new ServiceException("TypeDefinition Object is not exist" ,CommonMsgEnum.FAIL.getCode());
        }
    }

    /**
     * 保存属性排序
     * @param localAttributeSortDTO
     */
    @Override
    public void saveSortAttribute(LocalAttributeSortDTO localAttributeSortDTO) {
        deleteSort(localAttributeSortDTO);
        sortLocalAttribute(localAttributeSortDTO);
    }

    /**
     * 删除类型下排序
     * @param localAttributeSortDTO
     */
    private void deleteSort(LocalAttributeSortDTO localAttributeSortDTO) {
        LambdaQueryWrapper<TypeLocalAttributeSort> localAttributeSortQw = new LambdaQueryWrapper<>();
        localAttributeSortQw
//               .in(TypeLocalAttributeSort::getGlobalAttributeId, localAttributeSortDTO.getList().stream().map(SortDTO::getAttributeId).collect(Collectors.toList()))
                .eq(TypeLocalAttributeSort::getTypeId, localAttributeSortDTO.getTypeId())
                .eq(TypeLocalAttributeSort::getDeleted, DeleteFlagEnum.NO.getValue());
        localAttributeSortService.remove(localAttributeSortQw);
    }

    //插入新的排序
    private void sortLocalAttribute(LocalAttributeSortDTO localAttributeSortDTO) {
        List<TypeLocalAttributeSort> sorts = new ArrayList<>();
        localAttributeSortDTO.getList().stream().forEach(localAttribute -> {
            TypeLocalAttributeSort sort = new TypeLocalAttributeSort();
            sort.setTypeId(localAttributeSortDTO.getTypeId());
            sort.setCreator(ContextUtil.getCurrentUser());
            sort.setModifier(ContextUtil.getCurrentUser());
            sort.setGlobalAttributeId(localAttribute.getAttributeId());
            sort.setSortId(localAttribute.getSortId());
            sort.setObjectClass(sort.getClass().getName());
            sorts.add(sort);
        });
        localAttributeSortService.saveBatch(sorts);
    }

    /**
     * 更新子类型的Reference Class和Reference Table
     * @param typeId
     * @param typeDefinitionDTO
     */
    private void updateChildrenReferenceClass(Long typeId, TypeDefinitionDTO typeDefinitionDTO){
        List<TypeDefinition> typeDefinitions = this.queryByParentId(typeId);
        if(CollectionUtils.isEmpty(typeDefinitions)){
            return ;
        }
        List<Long> masterIds = typeDefinitions.stream().map(TypeDefinition::getMasterId).collect(Collectors.toList());
        Map<Long, TypeDefinitionMaster> masterMap = typeDefinitionMasterService.queryById(masterIds);
        if(CollectionUtils.isEmpty(masterMap)){
            return ;
        }
        List<TypeDefinitionMaster> masters = masterMap.values().stream().map(typeDefinitionMaster -> {
            typeDefinitionMaster.setReferenceClass(typeDefinitionDTO.getReferenceClass());
            typeDefinitionMaster.setReferenceTable(typeDefinitionDTO.getReferenceTable());
            typeDefinitionMaster.setModifier(ContextUtil.getCurrentUser());
            typeDefinitionMaster.setModifyTime(LocalDateTime.now());
            return typeDefinitionMaster;
        }).collect(Collectors.toList());
        typeDefinitionMasterService.saveBatch(masters);

        typeDefinitions.forEach(typeDefinition ->{
            updateChildrenReferenceClass(typeDefinition.getId(), typeDefinitionDTO);
        });
    }

    /**
     * 保存或更新类型定义校验
     * @param typeDefinitionDTO
     * @return
     */
    private String checkTypeDefinition(TypeDefinitionDTO typeDefinitionDTO, boolean isCreate){
        StringBuilder builder = new StringBuilder();
        if(StringUtils.isEmpty(typeDefinitionDTO.getInternalName())){
            builder.append("Internal Name cannot be empty!");
        }
        if(StringUtils.isEmpty(typeDefinitionDTO.getDisplayName())){
            builder.append("Display Name cannot be empty!");
        }
        if(isCreate){
            boolean isValid = typeDefinitionDTO.getInternalName().matches("^[0-9a-zA-Z_]{1,}$");
            if (!isValid) {
                builder.append("Internal name could only contain letter,number and \"_\"!");
            }

            if( !CollectionUtils.isEmpty(findByInternalName(typeDefinitionDTO.getInternalName()))) {
                builder.append("You cannot use the internal name which are being used in type definition!");
            }
        }else{
            if(typeDefinitionDTO.getId() == null){
                builder.append("TypeDefinition id cannot be empty!");
            }
        }
        return builder.toString();
    }

    /**
     * 装配类型属性
     * @param typeDefinitionDTO
     * @param typeDefinition
     * @param map
     */
    public void assembleTypeDefinitionDTO(TypeDefinitionDTO typeDefinitionDTO, TypeDefinition typeDefinition, Map<Long, TypeDefinitionMaster> map) {
        BeanUtils.copyProperties(typeDefinition, typeDefinitionDTO);
        typeDefinitionDTO.setInternalName(map.get(typeDefinition.getMasterId()).getName());
        typeDefinitionDTO.setReferenceClass(map.get(typeDefinition.getMasterId()).getReferenceClass());
        typeDefinitionDTO.setReferenceTable(map.get(typeDefinition.getMasterId()).getReferenceTable());
    }



    /**
     * 装配subTypes
     * @param typeDefinitionDTO
     * @param mapTypeDefinition
     * @param masterName
     */
    public void getNodeTypeDefinitionDTO(TypeDefinitionDTO typeDefinitionDTO, Map<Long, List<TypeDefinition>> mapTypeDefinition, Map<Long, TypeDefinitionMaster> masterName) {
        if (mapTypeDefinition.containsKey(typeDefinitionDTO.getId())) {
            typeDefinitionDTO.setSubTypes(mapTypeDefinition.get(typeDefinitionDTO.getId()).stream().map(typeDefinition -> {
                TypeDefinitionDTO typeDTO = new TypeDefinitionDTO();
                assembleTypeDefinitionDTO(typeDTO, typeDefinition, masterName);
                getNodeTypeDefinitionDTO(typeDTO, mapTypeDefinition, masterName);
                return typeDTO;
            }).collect(Collectors.toList()));
        }
    }

    @Override
    public TypeDefinition getRootTypeDefinition(Long typeId) {
        TypeDefinition typeDefinition = this.getById(typeId);
        if(typeDefinition == null) {
            return null;
        }
        if (typeDefinition.getParentTypeId() == ROOT_TYPE_ID) {
            return typeDefinition;
        } else {
            return getRootTypeDefinition(typeDefinition.getParentTypeId());
        }
    }


    @Override
    public TypeDefinitionDTO findTypeDefinitionAttributeRecursion(TypeDefinition definition) {
        this.initDataType();
        // 所有需要使用的属性
        List<Long> listAllTypeId = new ArrayList();
        // 获取当前类型树
        TypeDefinitionDTO typeDefinitionDTO = assembleOnlyAllTypeDefinitionDTO(definition);
        getTypeDefinitionDTOIds(listAllTypeId, Arrays.asList(typeDefinitionDTO));
        List<TypeDefinition> parentTypeDefinition = findParentTypeDefinition(definition.getParentTypeId());
        List<Long> parentIds = parentTypeDefinition.stream().map(TypeDefinition::getId).collect(Collectors.toList());
        listAllTypeId.addAll(parentIds);
        // 获取及组装类型，key为typeid，value为LocalAttributeDTO
        Map<Long, List<LocalAttributeDTO>> localAttributeDTOByMemory = getLocalAttributeDTOByMemory(listAllTypeId);
        // 组装类型及属性
        List<LocalAttributeDTO> listParent = new ArrayList();
        parentIds.stream().forEach(parentId -> {
            listParent.addAll(localAttributeDTOByMemory.get(parentId));
        });
        assumeTypeDefinitionDTOWithLocalAttributeDTO(typeDefinitionDTO, localAttributeDTOByMemory, listParent.stream().map(parentLocal -> {
            parentLocal.setLocalAttrType(LOCAL_ATTR_TYPE_PARENT);
            return parentLocal;
        }).collect(Collectors.toList()));
        return typeDefinitionDTO;
    }

    public TypeDefinitionDTO assembleOnlyAllTypeDefinitionDTO(TypeDefinition definition) {
        TypeDefinitionDTO typeDefinitionDTO = new TypeDefinitionDTO();

        LambdaQueryWrapper<TypeDefinition> typeDefinitionQw = new LambdaQueryWrapper<>();
        typeDefinitionQw.eq(TypeDefinition::getLatestIteration, true).eq(TypeDefinition::getDeleted, DeleteFlagEnum.NO.getValue());
        List<TypeDefinition> listTypeDefinition = this.list(typeDefinitionQw);

        Map<String, Object> mapMaster = new HashMap<>();
        List masterIds = listTypeDefinition.stream().map(TypeDefinition::getMasterId).collect(Collectors.toList());
        mapMaster.put("deleted", 0);

        LambdaQueryWrapper<TypeDefinitionMaster> typeDefinitionMasterQw = new LambdaQueryWrapper<>();
        typeDefinitionMasterQw.in(TypeDefinitionMaster::getId, masterIds).eq(TypeDefinitionMaster::getDeleted, DeleteFlagEnum.NO.getValue());
        List<TypeDefinitionMaster> masters = typeDefinitionMasterService.list(typeDefinitionMasterQw);
        Map<Long, TypeDefinitionMaster> masterIdMap = masters.stream().collect(Collectors.toMap(TypeDefinitionMaster::getId, Function.identity() ));
        HashMap<Long, List<TypeDefinition>> mapTypeDefinition =
                (HashMap<Long, List<TypeDefinition>>) listTypeDefinition.stream().collect(Collectors.groupingBy(TypeDefinition::getParentTypeId, Collectors.toList()));
        if (mapTypeDefinition.containsKey(definition.getParentTypeId())) {
            assembleTypeDefinitionDTO(typeDefinitionDTO, definition, masterIdMap);
            getNodeTypeDefinitionDTO(typeDefinitionDTO, mapTypeDefinition, masterIdMap);
        }
        return typeDefinitionDTO;
    }

    public void getTypeDefinitionDTOIds(List<Long> listId, List<TypeDefinitionDTO> typeDefinitionDTOList) {
        if (!CollectionUtils.isEmpty(typeDefinitionDTOList)) {
            listId.addAll(typeDefinitionDTOList.stream().map(TypeDefinitionDTO::getId).collect(Collectors.toList()));
            typeDefinitionDTOList.forEach(typeDefinitionDTO -> {
                getTypeDefinitionDTOIds(listId, typeDefinitionDTO.getSubTypes());
            });
        }
    }

    private void assumeTypeDefinitionDTOWithLocalAttributeDTO(TypeDefinitionDTO typeDefinitionDTO, Map<Long, List<LocalAttributeDTO>> localAttributeDTOByMemory,
                                                              List<LocalAttributeDTO> listParent) {
        List localAttributeList = localAttributeDTOByMemory.getOrDefault(typeDefinitionDTO.getId(), new ArrayList<>()).stream().map(localAttributeDTO -> {
            localAttributeDTO.setLocalAttrType(LOCAL_ATTR_TYPE_LOCAL);
            return localAttributeDTO;
        }).collect(Collectors.toList());
        localAttributeList.addAll(listParent);
        // todo设置排序和分组
        typeDefinitionDTO.setLocalAttributes(localAttributeList);
        if (!CollectionUtils.isEmpty(typeDefinitionDTO.getSubTypes())) {
            typeDefinitionDTO.getSubTypes().stream().forEach(typeDefinitionDTO1 -> {
                assumeTypeDefinitionDTOWithLocalAttributeDTO(typeDefinitionDTO1, localAttributeDTOByMemory,
                        typeDefinitionDTO.getLocalAttributes().stream().map(localAttributeDTO -> {
                            localAttributeDTO.setLocalAttrType(LOCAL_ATTR_TYPE_PARENT);
                            return localAttributeDTO;
                        }).collect(Collectors.toList()));
            });
        }
    }

    @Override
    public void deleteAttributeSort(Long localAttributeLinkId, Long typeId) {
        LambdaQueryWrapper<TypeLocalAttributeSort> qw = new LambdaQueryWrapper();
        qw.eq(TypeLocalAttributeSort::getTypeId, typeId).eq(TypeLocalAttributeSort::getGlobalAttributeId, localAttributeLinkId);
        List<TypeLocalAttributeSort> list = localAttributeSortService.list(qw);
        if (!CollectionUtils.isEmpty(list)) {
            localAttributeSortService.removeById(list.get(0));
        }

    }

    @Override
    public List<TypeDefinition> findAll() {
        LambdaQueryWrapper<TypeDefinition> qw = new LambdaQueryWrapper();
        qw.eq(TypeDefinition::getDeleted, DeleteFlagEnum.NO.getValue());
        return list(qw);
    }

    @Override
    public void groupSort(GroupSortDTO groupSortDTO) {
        // 根据typeId查询所有组，修改sortid
        // 查看类型权限
        TypeDefinition typeDefinition = getById(groupSortDTO.getTypeId());
       
        Map<String, Object> map = new HashMap<>();
        List<TypeAttributeGroupSort> listGroupSort = attributeGroupSortService.getByTypeId(groupSortDTO.getTypeId());
        Map<Long, Long> groupMap = groupSortDTO.getList().stream().collect(Collectors.toMap(SortDTO::getId, SortDTO::getSortId));

        List<TypeAttributeGroupSort> afterSort = listGroupSort.stream().map(groupSort -> {
            TypeAttributeGroupSort TypeAttributeGroupSort = groupSort;
            TypeAttributeGroupSort.setSortId(groupMap.getOrDefault(TypeAttributeGroupSort.getGroupId(), 0L));
            groupMap.remove(TypeAttributeGroupSort.getGroupId());
            return TypeAttributeGroupSort;
        }).collect(Collectors.toList());
        if (groupMap.size() > 0) {
            groupMap.keySet().stream().forEach(groupSortId -> {
                TypeAttributeGroupSort TypeAttributeGroupSort = new TypeAttributeGroupSort();
                TypeAttributeGroupSort.setSortId(groupMap.get(groupSortId));
                TypeAttributeGroupSort.setTypeId(groupSortDTO.getTypeId());
                TypeAttributeGroupSort.setGroupId(groupSortId);
                afterSort.add(TypeAttributeGroupSort);
            });
        }
        attributeGroupSortService.saveOrUpdateBatch(afterSort);
    }

    @Override
    public TypeDefinitionTreeDTO findTypeMultipleLevelTree(String typeInternalName) {
        return findTypeMultipleLevelTree(queryByTypeInternalName(typeInternalName));
    }

    @Override
    public TypeDefinitionTreeDTO findTypeMultipleLevelTree(long typeId) {
        return findTypeMultipleLevelTree(getById(typeId));
    }

    @Override
    public TypeDefinition queryByTypeInternalName(String typeInternalName) {
        LambdaQueryWrapper<TypeDefinitionMaster> typeDefinitionMasterQw = new LambdaQueryWrapper<>();
        typeDefinitionMasterQw.eq(TypeDefinitionMaster::getName, typeInternalName).eq(TypeDefinitionMaster::getDeleted, DeleteFlagEnum.NO.getValue());
        List<TypeDefinitionMaster> all = typeDefinitionMasterService.list(typeDefinitionMasterQw);
        if (CollectionUtils.isEmpty(all)) {
            return null;
        } else if (all.size() > 1) {
            throw new RuntimeException("Multiple result was found when query a unique object!");
        } else {
            Long id = all.get(0).getId();
            LambdaQueryWrapper<TypeDefinition> typeDefinitionQw = new LambdaQueryWrapper<>();
            typeDefinitionQw.eq(TypeDefinition::getMasterId, id).eq(TypeDefinition::getDeleted, DeleteFlagEnum.NO.getValue());
            List<TypeDefinition> all1 = list(typeDefinitionQw);
            return all1.get(0);
        }

    }

    @Override
    public TypeDefinitionTreeDTO findTypeMultipleLevelTree(TypeDefinition definition) {

        if (definition == null) {
            return null;
        }
        TypeDefinitionTreeDTO typeDefinitionTreeDTO = new TypeDefinitionTreeDTO();
        LambdaQueryWrapper<TypeDefinition> typeDefinitionQw = new LambdaQueryWrapper<>();
        typeDefinitionQw.eq(TypeDefinition::getLatestIteration, true).eq(TypeDefinition::getDeleted, DeleteFlagEnum.NO.getValue());
        List<TypeDefinition> listTypeDefinition = list(typeDefinitionQw);

        LambdaQueryWrapper<TypeDefinitionMaster> typeDefinitionMasterQw = new LambdaQueryWrapper<>();
        List typeId = listTypeDefinition.stream().map(TypeDefinition::getMasterId).collect(Collectors.toList());
        typeDefinitionMasterQw.eq(TypeDefinitionMaster::getDeleted, DeleteFlagEnum.NO.getValue()).in(TypeDefinitionMaster::getId, typeId);
        Map<Long, TypeDefinitionMaster> masterMap = typeDefinitionMasterService.list(typeDefinitionMasterQw).stream().collect(
                        Collectors.toMap(TypeDefinitionMaster::getId, Function.identity()));

        HashMap<Long, List<TypeDefinition>> mapTypeDefinition =
                (HashMap<Long, List<TypeDefinition>>) listTypeDefinition.stream().collect(Collectors.groupingBy(TypeDefinition::getParentTypeId, Collectors.toList()));
        if (mapTypeDefinition.containsKey(definition.getId())) {
            assembleTypeDefinitionDTO(typeDefinitionTreeDTO, mapTypeDefinition.get(definition.getParentTypeId()).get(0), masterMap);
            getNodeTypeDefinitionDTO(typeDefinitionTreeDTO, mapTypeDefinition, masterMap);
        }
        return typeDefinitionTreeDTO;
    }

    private void getNodeTypeDefinitionDTO(TypeDefinitionTreeDTO typeDefinitionTreeDTO, Map<Long, List<TypeDefinition>> mapTypeDefinition, Map<Long, TypeDefinitionMaster> masterMap) {
        if (mapTypeDefinition.containsKey(typeDefinitionTreeDTO.getId())) {
            typeDefinitionTreeDTO.setSubTypes(mapTypeDefinition.get(typeDefinitionTreeDTO.getId()).stream().map(typeDefinition -> {
                TypeDefinitionTreeDTO typeDTO = new TypeDefinitionTreeDTO();
                assembleTypeDefinitionDTO(typeDTO, typeDefinition, masterMap);
                getNodeTypeDefinitionDTO(typeDTO, mapTypeDefinition, masterMap);
                return typeDTO;
            }).collect(Collectors.toList()));
        }
    }

    private void assembleTypeDefinitionDTO(TypeDefinitionTreeDTO typeDefinitionTreeDTO, TypeDefinition TypeDefinition, Map<Long, TypeDefinitionMaster> map) {
        BeanUtils.copyProperties(TypeDefinition, typeDefinitionTreeDTO);
        typeDefinitionTreeDTO.setInternalName(map.get(TypeDefinition.getMasterId()).getName());
        typeDefinitionTreeDTO.setReferenceClass(map.get(TypeDefinition.getMasterId()).getReferenceClass());
        typeDefinitionTreeDTO.setReferenceTable(map.get(TypeDefinition.getMasterId()).getReferenceTable());
    }
}




